package de.unikoblenz.west.csxpoi.server.connector;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.BindingSet;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.http.HTTPRepository;
import de.unikoblenz.west.csxpoi.server.*;

/**
 * RDF Connector to STEVIE datastore
 * 
 * @author Yassin Nachite, Max Braun
 *
 */
public class StevieRDFConnector extends SesameConnector {

	public StevieRDFConnector(String serverAdress, String repositoryID) {
		super(serverAdress, repositoryID);
	}

	public List<BindingSet> sendRequest(String rdfQuery) {
		try {
			try {
				connection = repository.getConnection();
				ArrayList<BindingSet> resultList = new ArrayList<BindingSet>();
				TupleQuery query = connection.prepareTupleQuery(
						QueryLanguage.SPARQL, rdfQuery);
				TupleQueryResult result = query.evaluate();

				try {
					while (result.hasNext()) {
						resultList.add(result.next());
					}
					return resultList;
				} catch (QueryEvaluationException e) {
					throw new ServerException();
				} finally {
					result.close();
					connection.close();
				}

			} catch (QueryEvaluationException e) {
				throw new ServerException();
			} catch (RepositoryException e) {
				throw new ServerException();
			} catch (MalformedQueryException e) {
				throw new ServerException();
			}

		} catch (ServerException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public List<String> formatResult(String result) {

		return null;
	}

	@Override
	public List<String> baseRequest(String[] args) {
		try {
			String query = "PREFIX base: <" + Constants.NS_BASE + "> "
					+ "PREFIX rdf: <" + Constants.NS_RDF
					+ "> "
					+ "PREFIX rdfs: <"
					+ Constants.NS_RDFS
					+ "> "
					+ "SELECT ?s ?p ?o WHERE {"
					+ " ?s ?p ?o ."
					+ " FILTER (regex(str(?s), \"^"
					+ Constants.NS_BASE
					+ "\") ||"
					+ "  regex(str(?o), \"^"
					+ Constants.NS_BASE
					+ "\"))"
					+ " FILTER (?s != ?o)"
					+ // no self-subclasses/subproperties
					" FILTER (?p != rdf:type || ?o != base:Poi)"
					+ // no POIs
					" FILTER (?p != rdfs:subClassOf || ?o != base:Poi)"
					+ // no categories
					" FILTER (?p != rdf:type || ?o != base:Category)"
					+ // no categories
					" OPTIONAL {"
					+ "  ?contribution rdfs:subClassOf base:Contribution ."
					+ "  FILTER (?o = ?contribution)" + " }"
					+ " FILTER (?p != rdf:type || !bound(?contribution))" + // no
																			// contributions
					" FILTER (?p != rdf:type || ?o != base:User)" + // no users
					" FILTER (?o != rdfs:Resource)" + "} ORDER BY ASC(str(?s))";
			return formatResult(sendRequest(query), true);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public List<String> contributionRequest(String[] args) {
		try {
			String query = "PREFIX base: <"
					+ Constants.NS_BASE
					+ "> "
					+ "PREFIX rdfs: <"
					+ Constants.NS_RDFS
					+ "> "
					+ "SELECT ?s ?p ?o WHERE {"
					+ " ?s a base:Contribution ;"
					+ "  base:issuedAt ?issuedAt ."
					+ " ?s ?p ?o ."
					+ (!args[0].equals("") ? " FILTER (?s = <" + args[1] + ">)"
							: "") + " FILTER (?o != rdfs:Resource)"
					+ "} ORDER BY ASC(?issuedAt)";
			return formatResult(sendRequest(query), true);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public List<PoiWrapper> poiRequest(String[] args) {
		try {
			String query = "PREFIX base: <"
					+ Constants.NS_BASE
					+ "> "
					+ "PREFIX rdfs: <"
					+ Constants.NS_RDFS
					+ "> "
					+ "SELECT ?s ?p ?o WHERE {"
					+ " ?s a base:Poi ."
					+ " ?creation a base:PoiCreation ;"
					+ "  base:affectsPoi ?s ;"
					+ "  base:issuedAt ?issuedAt ."
					+ " ?s ?p ?o ."
					+ (!args[0].equals("") ? " FILTER (?s = <" + args[1] + ">)"
							: "") + " FILTER (?o != rdfs:Resource)"
					+ "} ORDER BY ASC(?issuedAt)";

			return null;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public List<String> userRequest(String[] args) {
		try {
			String query =

			"PREFIX base: <" + Constants.NS_BASE + "> " + "PREFIX foaf: <"
					+ Constants.NS_FOAF + "> " + "PREFIX rdfs: <"
					+ Constants.NS_RDFS + "> " + "SELECT ?s ?p ?o WHERE {"
					+ " ?s a base:User ;" + "  foaf:nick ?username ."
					+ " ?s ?p ?o ." + " FILTER (?p != base:password)"
					+ " FILTER (?p != foaf:mbox)"
					+ " FILTER (?p != foaf:knows)"
					+ " FILTER (?o != rdfs:Resource)"
					+ "} ORDER BY ASC(?username)";

			return formatResult(sendRequest(query), true);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public List<String> vocabularyRequest(String[] args) {
		try {
			String query = "PREFIX base: <" + Constants.NS_BASE + "> "
					+ "PREFIX rdfs: <" + Constants.NS_RDFS + "> "
					+ "SELECT ?s ?p ?o WHERE {"
					+ " ?s rdfs:subClassOf base:Poi ;" + "  rdfs:label ?name ."
					+ " ?s ?p ?o ." + " FILTER (?s != ?o)"
					+ // no self-subclasses
					" FILTER (?o != rdfs:Resource)"
					+ " FILTER (?s != base:Poi)" + "} ORDER BY ASC(?name)";

			return formatResult(sendRequest(query), true);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public List<CategoryWrapper> categoryRequest(String[] args) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<String> formatResult(List<String> data) {
		// TODO Auto-generated method stub
		return null;
	}
	
	public List<String> formatResult(List<BindingSet> data, boolean binding) {

		return null;
	}
	
}
